/**
 * TP numero: 1
 * 
 * Titre du TP : Bioctet
 * 
 * Author: NGUYEN Minh Tu, NGUYEN Quang Hoang
 * 
 * Version: 1.0
 * 
 * Remarques : compiler en Eclipse.
 */

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;


public class MainProg {
	public static void main(String[] args){
		if (args.length == 0) System.out.println("Syntaxe: bioctetscoder <sourceFile> <destinationFile>");
		if ((args.length != 0) && (args.length != 2)) System.out.println("Syntaxe: bioctetscoder <source> <destination>");
		if (args.length == 2){
			String sourceFile = args[0];
			String destFile = args[1];
			CoderBioctets coder = new CoderBioctets(sourceFile);
			
			FileInputStream inStream = null;
			FileOutputStream outStream = null;
			
			try{
				inStream = new FileInputStream(sourceFile);
				outStream = new FileOutputStream(destFile);
				
				byte[] buffer = new byte[2]; //a lire 2 bytes chaque fois 
		
				int bytes_read;
				System.out.println("Compressing...");			
				while((bytes_read = inStream.read(buffer)) != -1){
					String bioctetReaded = "" + (char)buffer[0] + (char)buffer[1];
					
					int code = coder.getCode(bioctetReaded);
					
					if ((code>>31) > 0){ //bit_de_poids_fort of 4_bytes_number = 1 -> coded by 4 bytes
						outStream.write(code);
					} 
					else if ((code>>15) > 0){//bit_de_poids_fort of 4_bytes_number = 1 -> coded by 2 bytes
						
						//ecrire un octet chaque fois
						int tam1=code>>8;
						int tam2= (code & 255);		
						outStream.write(tam1);
						outStream.write(tam2);
						
					}					
					else{ //bit_de_poids_fort = 0 -> coded by 1 byte
						outStream.write((byte)code);
					}
					
				}
				
				System.out.println("Out to compressed file Done!");
				
				File originalFile = new File(sourceFile);
				File zipFile = new File(destFile);
				
				long originalSize = originalFile.length();
				long zipSize = zipFile.length();
				double ratio = (double)zipSize / (double)originalSize;
				
				System.out.println("Original file's size: " + originalSize + " bytes");
				System.out.println("Compressed file's size: " + zipSize + " bytes");
				System.out.println("----> Compression ratio: " + ratio);
								
				inStream.close();
				outStream.close();
								
				//Decompresser
				System.out.println("Decompressing...");
				inStream = new FileInputStream(destFile);
				BufferedWriter out = new BufferedWriter(new FileWriter("decoded.txt"));
		
						while((bytes_read = inStream.read(buffer)) != -1){
							int code0 =(byte)buffer[0];
							int code1 =(byte)buffer[1];
							
							//prevenir le signed int du java
							if (code0 < 0) {
								code0 = 256-code0*(-1);
							}
							if (code1 < 0) {
								code1 = 256-code1*(-1);
							}
																
							int code = 0;
							code= (code0<<8) + code1;
							
							int codeToConsult = 0;
							while(true)
							{
								if(code == 65535){
									bytes_read = inStream.read(buffer);
									codeToConsult = 65535<<16 + (int)buffer[0] * 128 + (int)buffer[1];
									out.write(coder.getString(codeToConsult));
									break;
								}
								else if((code >> 15) > 0){
									codeToConsult = code;
									out.write(coder.getString(codeToConsult));
									break;
								}
								
								else{
									codeToConsult = code>>8;
									out.write(coder.getString(codeToConsult));	
								
									//lire 1 octet plus
									int c = inStream.read();
									if(c == -1){
										codeToConsult = code & 255;
										out.write(coder.getString(codeToConsult));
										break;
									}
									//concatener a code
									code = ((code & 255)<<8) + c;											
									continue;
								}
								
							}
							

							code = 0;					
						}				
				System.out.println("Decompression Done !");
				//end of program
				inStream.close();
				out.close();
				
			}catch (Exception e) {
				System.out.println(e);
			}
		}
	}
	
    
	
	public static final byte[] intToByteArray(int value) {
        return new byte[] {
                (byte)(value >>> 24),
                (byte)(value >>> 16),
                (byte)(value >>> 8),
                (byte)value};
    }
    
    public static int byteArrayToInt(byte[] b, int offset) {
        int value = 0;
        for (int i = 0; i < 4; i++) {
            int shift = (4 - 1 - i) * 8;
            value += (b[i + offset] & 0x000000FF) << shift;
        }
        return value;
    }
}